.text
.global journey
.global idt, gdt
.global idle_task_struct, kp_dir
.global go_here
.global kp_0,kp_1,kp_2

__PAGE_OFFSET=0xC0000000
#define pa(X) ((X) - __PAGE_OFFSET)

journey:
	movl	$0x10, %eax
	movl	%eax, %ds
	movl	%eax, %es
	movl	%eax, %fs
	movl	%eax, %gs

	xorl	%eax, %eax
check_a20:
	incl	%eax
	movl	%eax, 0x000000
	cmpl	%eax, 0x100000
	je	check_a20

do_move:
	cld	
	movl	$0x24000, %ecx		# max value is 0x90000 / 4
change:	
	movl	$0x10000, %esi
	movl	$0x100000, %edi
	rep
	movsl

	#very tricky. we need a very special jump
	.byte 0xea
	.long pa(go_here) 
	.word 0x8

	#we are more safe now
go_here:
	lgdt pa(gdt_descr)
	movl	$0x10, %eax
	movl	%eax, %ds
	movl	%eax, %es
	movl	%eax, %fs
	movl	%eax, %gs

	# clear the bss region, set static var to 0
	cld
	movl	$pa(_bss), %edi
	movl	$pa(_ebss), %ecx
	subl	%edi, %ecx	# %ecx is the bss length
	xorl	%eax, %eax
	rep
	stosb

	movl 	%cr0, %eax		# check math chip
	andl	$0x80000011, %eax	# save PG, ET, PE
					# 31	4  3  2  1  0
					# PG... ET TS EM MP PE
	testl	$0x10, %eax		# ET is set if having 387
	jne	1f	
	orl	$0x04, %eax		# emulate by software
1:
	movl	%eax, %cr0
	finit

setup_paging:
#	movl	$pa(kp_1) + 4092, %edi
#	movl	$0x007ff007, %eax	#  8M - 4096 + 7 (r/w u/s, p)

#	std
#fill_pg:
#	stosl
#	subl	$0x1000, %eax
#	jge	fill_pg
	
	movl $pa(kp_0),%edi
	movl $007,%eax

	cld
8:
	stosl
	add $0x1000,%eax
	cmp $pa(kp_2),%edi
	jne 8b

	#enable paging
	movl	$pa(kp_dir), %eax
	movl	%eax, %cr3
	movl	%cr0, %eax
	orl	$0x80000000, %eax
	movl	%eax, %cr0
	#jmp 	3f
	.byte 0xea
	.long 3f
	.word 0x8

3:
	#now we have enabled the paging
	#setup the stack pointer
	lss	stack_start,%esp

	#setup initial idt
	call setup_idt

	#Note that we load the new GDT descriptor table here.
	#The contents of the new one are the same with the old one.
	#We need to reload it using the virtual GDT address, because
	#after the kernel is moved up to 0xC0000000, we want to clear 
	#all used page directory entries which are mapped to address range
	#which is < 0xC0000000. If we do not load the new GDT again here,
	#we will be in trouble of page fault whenever there are context
	#switches(interrupts). Why? Because the GDT register have the old value
	#which always points to an invalid range which are not mapped
	#by the kernel anymore.
	call setup_gdt

	#go
	#call (main)
	pushl	$0			# params for main
	pushl	$0
	pushl	$0
	pushl	$hang			# ret addr for main
	pushl	$main			
	ret

	#should never comeback
hang:
	jmp hang

	.align 2
ignore_int:
	incb 0xb8000 + 160		# put something on the screen
	movb $2, 0xb8000 + 161		# this would let us know something 
	iret				# happened

# idt descriptor
# 7-6             5 - 4	     3-2 1-0
# offset(31...16) Attributes sel offset(15...0)
setup_idt:
	lea 	ignore_int, %edx
	movl 	$0x00080000, %eax	# sel = 0x0008 == cs
	movw	%dx, %ax			
	movw	$0x8E00, %dx		# interrupt gate - dpl = 0, present
					# the high part in %edx contains ign...

	movl	$idt, %edi
	movl	$256, %ecx
rp_sidt:
	movl	%eax, (%edi)
	movl	%edx, 4(%edi)
	addl	$8, %edi
	decl 	%ecx
	jne	rp_sidt
	lidt	idt_pdesc
	ret

setup_gdt:
	lgdt	gdt_new_descr
	ret

	.align 2
idt_pdesc:
	.word 256 * 8 - 1		# idt contains 256 entries
	.long idt	

	.align 2
gdt_descr:
	.word	256 * 8 - 1	# gdt limit = 24, 3 GDT entries
	.long	gdt-__PAGE_OFFSET 

gdt_new_descr:
	.word	256 * 8 - 1	# gdt limit = 24, 3 GDT entries
	.long	gdt

.org 0x1000
idle_task_struct:

.org 0x2000
kp_dir:
	.long 0x00103007
	.long 0x00104007
	.fill 512-2,4,0
	.long 0x00103007
	.long 0x00104007
	.fill 256-2,4,0
	.long 0x00103007
	.long 0x00104007
	.fill 256-2,4,0

.org 0x3000
kp_0:

.org 0x4000
kp_1:

.org 0x5000
kp_2:

	.align 8
idt:	
	.fill 256, 8, 0

	.align 8
gdt:
	.word 0, 0, 0, 0
	
	# kernel cs 0x08
	.word 0xffff	# base: 0, limit: 4G
	.word 0x0000
	.word 0x9a00
	.word 0x00cf

	# kernel ds 0x10
	.word 0xffff	# base: 0, limit: 4G
	.word 0x0000
	.word 0x9200
	.word 0x00cf

	# user cs 0x1b
	.word 0xffff	# base: 0, limit: 4G
	.word 0x0000
	.word 0xfa00	 
	.word 0x00cf

	# user ds 0x23
	.word 0xffff	# base: 0, limit: 4G
	.word 0x0000
	.word 0xf200
	.word 0x00cf

	# tss descriptor
	.word 0, 0, 0, 0

	# for ldt, one each process

	.fill 250, 8, 0	# not necessary to have so many
